package com.iakuil.app.mpg;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.iakuil.app.common.core.domain.BaseEntity;
import com.iakuil.app.common.core.util.MapUtils;
import jakarta.validation.constraints.NotNull;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 定制的代码生成引擎
 *
 * @author Kai
 * @date 2022/1/26 3:19
 **/
public class CustomTemplateEngine extends VelocityTemplateEngine {

    @Override
    public AbstractTemplateEngine batchOutput() {
        try {
            ConfigBuilder config = this.getConfigBuilder();
            List<TableInfo> tableInfoList = config.getTableInfoList();
            tableInfoList.forEach(tableInfo -> {
                Map<String, Object> objectMap = this.getObjectMap(config, tableInfo);
                Optional.ofNullable(config.getInjectionConfig()).ifPresent(t -> {
                    t.beforeOutputFile(tableInfo, objectMap);
                    // 输出自定义文件
                    outputCustomFile(t.getCustomFiles(), tableInfo, objectMap);
                });
                // Mp.java
                outputEntity(tableInfo, objectMap);
                // mapper and xml
                outputMapper(tableInfo, objectMap);
                // service
                outputService(tableInfo, objectMap);
                // XxxController.java
                outputController(tableInfo, objectMap);
                // DTO
                outputDto(tableInfo, objectMap);
                // Converter
                outputConverter(tableInfo, objectMap);
            });
        } catch (Exception e) {
            throw new RuntimeException("无法创建文件，请检查配置信息！", e);
        }
        return this;
    }

    private void outputDto(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        if (StringUtils.isNotBlank(tableInfo.getEntityName())) {
            // 从DTO删除一些无用的import
            removePackages(tableInfo, IdType.class, TableId.class, TableName.class, BaseEntity.class);

            String entityName = tableInfo.getEntityName();
            String dtoFile = String.format((MapUtils.getStr(objectMap, GenConstant.DTO_OUTPUT_KEY) + File.separator + tableInfo.getEntityName() + "Dto" + suffixJavaOrKt()), entityName);
            outputFile(new File(dtoFile), objectMap, "templates/dto.java.vm", true);

            String voFile = String.format((MapUtils.getStr(objectMap, GenConstant.DTO_OUTPUT_KEY) + File.separator + "vo" + File.separator + tableInfo.getEntityName() + "InfoVo" + suffixJavaOrKt()), entityName);
            outputFile(new File(voFile), objectMap, "templates/vo.java.vm", true);

            String addFile = String.format((MapUtils.getStr(objectMap, GenConstant.DTO_OUTPUT_KEY) + File.separator + "cmd" + File.separator + tableInfo.getEntityName() + "Add" + suffixJavaOrKt()), entityName);
            outputFile(new File(addFile), objectMap, "templates/add.java.vm", true);

            String editFile = String.format((MapUtils.getStr(objectMap, GenConstant.DTO_OUTPUT_KEY) + File.separator + "cmd" + File.separator + tableInfo.getEntityName() + "Edit" + suffixJavaOrKt()), entityName);
            outputFile(new File(editFile), objectMap, "templates/edit.java.vm", true);

            String queryFile = String.format((MapUtils.getStr(objectMap, GenConstant.DTO_OUTPUT_KEY) + File.separator + "query" + File.separator + tableInfo.getEntityName() + "Query" + suffixJavaOrKt()), entityName);
            outputFile(new File(queryFile), objectMap, "templates/query.java.vm", true);
        }
    }

    private void outputConverter(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        String dtoPath = getPathInfo(OutputFile.service) + File.separator + "converter";
        if (StringUtils.isNotBlank(tableInfo.getEntityName())) {
            String entityName = tableInfo.getEntityName();
            String converterFile = String.format((dtoPath + File.separator + entityName + "To" + entityName + "Dto" + "Converter" + suffixJavaOrKt()), entityName);
            outputFile(new File(converterFile), objectMap, "templates/converter.java.vm", true);
        }
    }

    private void removePackages(TableInfo tableInfo, Class<?>... clazz) {
        tableInfo.getImportPackages().removeIf(Arrays.stream(clazz).map(Class::getName).collect(Collectors.toSet())::contains);
    }
}
